package com.dudy.authdemo.config;

import com.dudy.authdemo.service.impl.JwtUserDetailServiceImpl;
import com.dudy.common.base.ResultCode;
import com.dudy.common.util.ResponseUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@Slf4j
@Component
public class JWTAuthenticationFilter extends OncePerRequestFilter {

    private static final String TOKEN_HEADER = "token";
    private static final String TOKEN_START = "helowin_";

    @Autowired
    private JwtUserDetailServiceImpl jwtUserDetailService;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Override
    protected void doFilterInternal(HttpServletRequest request, @NotNull HttpServletResponse response,
                                    @NotNull FilterChain chain) throws IOException, ServletException {

        String header = request.getHeader(TOKEN_HEADER);


        if (StringUtils.isNotBlank(header) && header.startsWith(TOKEN_START)) {
            String jwtToken = header.substring(TOKEN_START.length());
            String username = jwtTokenUtil.getUsernameFromToken(jwtToken);
            if (StringUtils.isBlank(username)) {
                response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
                response.setStatus(403);
                PrintWriter writer = response.getWriter();
                // 将登陆信息写回到前端
                writer.write(new ObjectMapper().writeValueAsString(ResponseUtils.getResponse(ResultCode.NOT_LOGIN.getCode(),"用户名无效，请联系管理员")));
                writer.flush();
                writer.close();
                return;
            }
            UserDetails userDetails = jwtUserDetailService.loadUserByUsername(username);

            // 验证token是否有效，登陆用户是否匹配
            if (jwtTokenUtil.validateToken(jwtToken, userDetails)) {
                response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
                response.setStatus(403);
                PrintWriter writer = response.getWriter();
                // 将登陆信息写回到前端
                writer.write(new ObjectMapper().writeValueAsString(ResponseUtils.getResponse(ResultCode.NOT_LOGIN.getCode(),"用户名无效，请联系管理员")));
                writer.flush();
                writer.close();
                return;
            }
            UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
                    new UsernamePasswordAuthenticationToken(
                            userDetails, userDetails.getPassword(), userDetails.getAuthorities());
            usernamePasswordAuthenticationToken
                    .setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
        }
        chain.doFilter(request, response);
    }

}